package route

import (
	"bytes"
	"fdfs/upload"
	"github.com/disintegration/imaging"
	"image"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

var url, field, token string
var once = sync.Once{}
var bl bool

func ImageRoute(w http.ResponseWriter, r *http.Request) {
	method := r.Method
	switch method {
	case "GET":
		TailoringImgRoute(w, r)
	case "DELETE":
		DeleteImgRoute(w, r)
	default:
		w.Write(Result{}.Fail("不支持该访问方式"))
	}
}

// 处理/upload 逻辑
func UploadRoute(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")             //允许访问所有域
	w.Header().Add("Access-Control-Allow-Headers", "Content-Type") //header的类型
	w.Header().Set("content-type", "application/json")
	if r.Method != "POST" {
		panic("不支持POST外的访问方式")
	}
	//认证功能
	r.ParseMultipartForm(32 << 20)
	file, handler, err := r.FormFile("file")
	defer func() {
		if err := recover(); err != nil {
			w.Write(Result{}.Fail(err))
		}
	}()
	boolCh := isAuthenticationUrlResult(r)
	defer close(boolCh)
	if err != nil {
		panic("获取上传 file上传出错")
	}
	if file == nil {
		panic("file文件不能为空")
	}
	ok := <-boolCh
	if !ok {
		panic("验证不通过")
	}
	data := upload.UploadUtils(file, handler)
	file.Close()
	w.Write(Result{}.Success(data))
}
func checkAuthentication(r *http.Request) (bool, string, string, string) {
	once.Do(func() {
		bl = upload.ConfigJson.IsAuthentication
		if upload.ConfigJson.Debug {
			bl = false
		}
		if bl {
			field = upload.ConfigJson.AuthenticationField
			if field == "" {
				panic("认证模式开启,认证字段不能为空")
			}
			url = upload.ConfigJson.AuthenticationUrl
			if url == "" {
				panic("认证模式开启,认证Url不能为空")
			}
		}
	})
	if bl {
		token = r.Header.Get(field)
		if token == "" {
			panic("认证模式开启,认证值不能为空")
		}
	}
	return bl, url, field, token
}
func getRequestAuthenticationUrl(url string, file string, token string) (chan *http.Response, chan error) {

	client := &http.Client{Timeout: 5 * time.Second}
	var bt bytes.Buffer
	bt.WriteString(url)
	bt.WriteString("?")
	bt.WriteString(file)
	bt.WriteString("=")
	bt.WriteString(token)
	ch := make(chan *http.Response)
	errCh := make(chan error)
	upload.Pool.Submit(func() {
		resp, err := client.Get(bt.String())
		errCh <- err
		ch <- resp
	})
	return ch, errCh
}
func isAuthenticationUrlResult(r *http.Request) chan bool {
	bl, url, file, token := checkAuthentication(r)
	boolCh := make(chan bool, 1)
	if !bl {
		boolCh <- true
		return boolCh
	}
	ch, errCh := getRequestAuthenticationUrl(url, file, token)
	defer close(errCh)
	defer close(ch)
	if <-errCh != nil {
		panic("第三方网络请求超时")
	}
	resp := <-ch
	defer resp.Body.Close()
	result, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic("第三方认证返回结果无法解析")
	}
	boolCh <- string(result) == "ok"
	return boolCh
}

// 对图片进行裁剪
func TailoringImgRoute(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")             //允许访问所有域
	w.Header().Add("Access-Control-Allow-Headers", "Content-Type") //header的类型
	defer func() {
		if err := recover(); err != nil {
			w.Write(Result{}.Fail(err))
		}
	}()
	path := upload.MatchingPath(r.URL.Path)
	expr := upload.GetImgType(path)
	file, err := os.Open(path)
	defer file.Close()
	if err != nil {
		panic("图片不存在")
	}
	query := r.URL.Query()
	wh := query.Get("w")
	h := query.Get("h")
	if wh == "" || h == "" {
		io.Copy(w, file)
		return
	}
	width, err := strconv.Atoi(wh)
	if err != nil {
		panic("width 参数错误")
	}
	hight, err := strconv.Atoi(h)
	if err != nil {
		panic("height 参数错误")
	}
	dsts := make(chan *image.NRGBA)
	defer close(dsts)
	upload.Pool.Submit(func() {
		log.Println("准备裁剪", "width ", width, "height ", hight)
		img, err := imaging.Decode(file)
		rectangle := img.Bounds()
		if width > rectangle.Dx() {
			width = rectangle.Dx()
		}
		if hight > rectangle.Dy() {
			hight = rectangle.Dy()
		}
		if err != nil {
			log.Fatal("打开文件错误")
			return
		}
		thumb := imaging.Resize(img, width, hight, imaging.CatmullRom)
		dsts <- thumb
	})
	upload.CreateImgType(expr, w, <-dsts)
}

func DeleteImgRoute(w http.ResponseWriter, r *http.Request) {

	path := upload.MatchingPath(r.URL.Path)
	ch := make(chan []byte)
	defer close(ch)
	upload.Pool.Submit(func() {
		err := os.Remove(path)
		if err != nil {
			ch <- Result{}.Fail("图片不存在")
		}
		ch <- Result{}.Success("")
	})
	w.Write(<-ch)
}
